package controllers.api;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import play.Logger;
import play.mvc.Controller;
import play.mvc.Router;
import models.Content;
import models.ContentTag;
import models.InboxMessage;
import models.Message;
import models.Message.Receiver;
import models.Notification;
import models.OutboxMessage;
import models.Subscriber;
import models.Tag;
import models.User;
import models.Message.SharedContent;

import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions.Method;

import static com.google.appengine.api.taskqueue.TaskOptions.Builder.*;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import controllers.Data;
import play.mvc.Http.StatusCode;
import play.mvc.Scope.Session;
import play.mvc.results.Error;
import utils.constants.SessionConstants;

public class Outbox extends MeApi {
	
	public static void list(Integer offset, Integer limit) {
		if(offset == null) offset = 0;
		if(limit==null || limit > LIMIT || limit==0) {
			limit = LIMIT;
		}
		User current = getCurrentUser();
		Data<OutboxMessage> data = new Data<OutboxMessage>();
		List<OutboxMessage> messages = OutboxMessage.paginate(OutboxMessage.findSent(current), offset, limit);
		data.total = OutboxMessage.countSent(current);
		data.data = messages;
		for(OutboxMessage message : messages) {
			 message.message.get();
		}
		renderTemplate("api/messageList.json",data);
	}
	
	
/*	public static void add_old(JsonObject body) {
		User from = getCurrentUser();
		String text = body.get("body").getAsString();
		List<SharedContent> sharedContents = new ArrayList<SharedContent>();
		for(JsonElement element : body.get("contents").getAsJsonArray()) {
			JsonObject contentElement = element.getAsJsonObject();
			String type = contentElement.get("type").getAsString();
			String source = contentElement.get("source").getAsString();
			Long id = contentElement.get("id").getAsLong();
			if(type==null) {
				Error error = new Error("Type field is empty.");
				error.apply(request, response);
				return;
			}
			Content.ContentType contentType = Content.ContentType.valueOf(type.toUpperCase());
			if(contentType == null) {
				Error error = new Error(type + " is not a correct type value.");
				error.apply(request, response);
				return;
			}
			if(source==null) {
				Error error = new Error("Source field is empty");
				error.apply(request, response);
				return;
			}
			if(id==null) {
				Error error = new Error("Id field is empty");
				error.apply(request, response);
				return;
			}
			
			SharedContent sharedContent = new Message().new SharedContent();
			sharedContent.type = contentType;
			sharedContent.id = id;
			sharedContent.source = source;
			sharedContents.add(sharedContent);
		}
		
		for(JsonElement element : body.get("receivers").getAsJsonArray()) {
			JsonObject toElement = element.getAsJsonObject();
			Long userId = toElement.get("id").getAsLong();
			String firstName = toElement.get("firstName").getAsString();
			if(userId == null) {
				Error error = new Error("The id field of " + firstName + " is empty.");
				error.apply(request, response);
				return;
			}
			User to = User.findById(userId);
			if(to == null) {
				Error error = new Error(firstName + " is not a registered user.");
				error.apply(request, response);
				return;
			}
			
			// INFO: Se crean dos mensajes para diferenciar las carpetas de outbox e inbox. Asi un usuario si lo elimina de la suya permanece en la otra.
			
			//Se inserta un mensaje que pertenece al emisor. // TODO esta parte esta duplicada, deberia ir fuera de la iteracion de receivers. Problema el to (deberia de ser una lista)
			Message message = new Message(from, from, to);
			message.text = text;
			message.contents = sharedContents;
			message.insert();
			//Se inserta un mensaje que pertenece al receptor
			
			message = new Message(to, from, to);
			message.text = text;
			message.contents = sharedContents;
			message.insert();
			Tag sharedTag = Tag.findOrCreateByName("shared", to);
			for(SharedContent sharedContent : sharedContents) {
				if(Content.ContentType.PHOTO == sharedContent.type) {
					ContentTag contentTag = new ContentTag(sharedContent.id, Content.ContentType.PHOTO, sharedTag);
					contentTag.save();
				}
			}
			Notification notification = new Notification();
			if(from.basic_information != null) {
				notification.message = from.basic_information.firstName 
						+ " " + from.basic_information.lastName + " ha compartido contigo " 
						+ sharedContents.size() + " contenidos.";
			} else {
				notification.message =  "El administrador ha compartido contigo " 
						+ sharedContents.size() + " contenidos.";
			}
			notification.owner = to;
			notification.type = Notification.NotificationType.INBOX;
			notification.insert();
		}
		ok();
	}
*/	
	public static void add(JsonObject body) {
		User from = getCurrentUser();
		String text = body.get("body").getAsString();
		if(text != null && !("").equals(text)) {
			text = text.trim();
		}
		List<SharedContent> sharedContents = new ArrayList<SharedContent>();
		for(JsonElement element : body.get("contents").getAsJsonArray()) {
			JsonObject contentElement = element.getAsJsonObject();
			String type = contentElement.get("type").getAsString();
			String source = contentElement.get("source").getAsString();
			Long id = contentElement.get("id") != null ? contentElement.get("id").getAsLong() : null;
			if(type==null) {
				Error error = new Error("Type field is empty.");
				error.apply(request, response);
				return;
			}
			Content.ContentType contentType = Content.ContentType.valueOf(type.toUpperCase());
			if(contentType == null) {
				Error error = new Error(type + " is not a correct type value.");
				error.apply(request, response);
				return;
			}
			if(source==null) {
				Error error = new Error("Source field is empty");
				error.apply(request, response);
				return;
			}
			// Se comenta esto para permitir contenido externo
			/*if(id==null) {
				Error error = new Error("Id field is empty");
				error.apply(request, response);
				return;
			}*/
			
			SharedContent sharedContent = new Message().new SharedContent();
			sharedContent.type = contentType;
			sharedContent.id = id;
			sharedContent.source = source;
			sharedContents.add(sharedContent);
		}
		
		ArrayList<User> receivers = new ArrayList<User>();
		for(JsonElement element : body.get("receivers").getAsJsonArray()) {
			JsonObject toElement = element.getAsJsonObject();
			Long userId = toElement.get("id").getAsLong();
			String firstName = toElement.get("firstName").getAsString();
			if(userId == null) {
				Error error = new Error("The id field of " + firstName + " is empty.");
				error.apply(request, response);
				return;
			}
			User to = User.findById(userId);
			if(to == null) {
				Error error = new Error(firstName + " is not a registered user.");
				error.apply(request, response);
				return;
			}
			
			receivers.add(to);
		}
			// INFO: Se crean dos mensajes para diferenciar las carpetas de outbox e inbox. Asi un usuario si lo elimina de la suya permanece en la otra.
			
		//Se inserta un mensaje que pertenece al emisor. // TODO esta parte esta duplicada, deberia ir fuera de la iteracion de receivers. Problema el to (deberia de ser una lista)
		Message message = new Message();
		message.from = from;
		//message.to = receivers;
		message.text = text;
		message.contents = sharedContents;
		
		for(User receiver : receivers) {
			message.addReceiver(receiver);
		}
		message.insert();
		
		// Create the outbox message
		OutboxMessage outMessage = new OutboxMessage(from, message);
		outMessage.save();	
		
				
		//Se inserta un mensaje que pertenece al receptor
			
		for(User receiver : receivers)	{
			InboxMessage inbox = new InboxMessage(receiver, message);
			inbox.save();
			
			 Tag sharedTag = Tag.findOrCreateByName("shared", receiver);
				for(SharedContent sharedContent : sharedContents) {
					if(Content.ContentType.PHOTO == sharedContent.type) {
						ContentTag contentTag = new ContentTag(sharedContent.id, Content.ContentType.PHOTO, sharedTag);
						contentTag.save();
					}
				}
				Notification notification = new Notification();
				if(from.basic_information != null) {
					StringBuffer textSb = new StringBuffer();
					textSb.append(from.basic_information.firstName).append(" ").
					append(from.basic_information.lastName).append(" te ha enviado un mensaje.");
					
					if(sharedContents.size() > 0) {
						textSb.append(" Tiene ").append(sharedContents.size()).append(" contenidos.");
					} 
					notification.message = textSb.toString();
					
				} else {
					notification.message =  "El administrador ha compartido contigo " 
							+ sharedContents.size() + " contenidos.";
				}
				notification.owner = receiver;
				notification.type = Notification.NotificationType.INBOX;
				notification.insert();
				
				// Creating a task for send an email with the notification.
				Queue queue = QueueFactory.getDefaultQueue();
				String residenceDomain = null;
				String username = Session.current().get(SessionConstants.USER);
				if(username.contains("@")){
					residenceDomain = username.substring(username.indexOf("@")+1);
				} else {
					residenceDomain = "";
				}
				
			    queue.add(withUrl("/task/notificate/mail").method(Method.POST).
			    		param("fromId", String.valueOf(from.id)).
			    		param("dstId", String.valueOf(receiver.id)).
			    		param("msgContent", message.text).
			    		param("numberAttach", String.valueOf(sharedContents.size())).
			    		param("residenceDomain", residenceDomain));
		}
		ok();
	}
	
	/*public static void migrateMessages() {
		User from = User.findById(new Long(26001));
		
		String text = "Aquí con los mejores leones!!!!";
		
		List<SharedContent> sharedContents = new ArrayList<SharedContent>();
		SharedContent sharedContent0 = new Message().new SharedContent();
		sharedContent0.type =  Content.ContentType.valueOf("PHOTO".toUpperCase());;
		sharedContent0.id = new Long(40001);
		sharedContent0.source = "/api/file/AMIfv97vY9YVIBbILz8cBUxiDz0ShCSNEgU-Y6ymC70c5cBzOM5kat984-tH4GFGknErKSFza-KsOMlm2BJaiyKTMfLgHjq6mZJCvhpZJdnCrvst2Y7whE99aklBrWW6FOHyO2l6PV1ZNayTdIGt-T0Y5zmco0v-Yg";
		sharedContents.add(sharedContent0);
		
		
		SharedContent sharedContent1 = new Message().new SharedContent();
		sharedContent1.type =  Content.ContentType.valueOf("PHOTO".toUpperCase());;
		sharedContent1.id = new Long(37005);
		sharedContent1.source = "/api/file/AMIfv95MewlUoqV9ygaXwbbRRbzfed6KPGWHsaQA1VKB9jr--L2B7luP3hKfewMoTHqyKp8zrpp9iPC2mRXHT73JmC4BgqhVLFlBy5ZfAatme6ki31kE8UPBVLnWDLDh6H9A4Ix1D0gdaV6CT3OpDfLZAJKn0agPjA";
		sharedContents.add(sharedContent1);
		
		SharedContent sharedContent2 = new Message().new SharedContent();
		sharedContent2.type =  Content.ContentType.valueOf("PHOTO".toUpperCase());;
		sharedContent2.id = new Long(36003);
		sharedContent2.source = "/api/file/AMIfv94ZLp7NJ-qq_WOS4Sy3YKPV6tnshTacHifwQvj1omAUbnSTbTU2fVsfthuvrTk0NqkRVFlWOwS6-pszn7bLWijvMUbV1Fg8qYwtzFE2kWFV20SZrVY7SReyGngmHzIOQVEeVxbVVphJdZVawOTRBNGkp9jbYA";
		sharedContents.add(sharedContent2);		
		
		SharedContent sharedContent3 = new Message().new SharedContent();
		sharedContent3.type =  Content.ContentType.valueOf("PHOTO".toUpperCase());;
		sharedContent3.id = new Long(40002);
		sharedContent3.source = "/api/file/AMIfv978EdqyIvpqL2E88-rD4yTbexhSxK86ELTpCLOU6lEGF9d3u4UWBneRukmIYfYibeBhR7Ig4CcF-XMevyTGsl9NF8HCganp7kLymyK5YALI7bAhdo6jFcq-FBoijDpJb-47MK0yUhwM_VzfdFtiBCNhNJNVMg";
		sharedContents.add(sharedContent3);		
		
		ArrayList<User> receivers = new ArrayList<User>();
		User to = User.findById(new Long(24001));
		receivers.add(to);
		
		// INFO: Se crean dos mensajes para diferenciar las carpetas de outbox e inbox. Asi un usuario si lo elimina de la suya permanece en la otra.
			
		//Se inserta un mensaje que pertenece al emisor. // TODO esta parte esta duplicada, deberia ir fuera de la iteracion de receivers. Problema el to (deberia de ser una lista)
		Message message = new Message();
		message.from = from;
		//message.to = receivers;
		message.text = text;
		message.contents = sharedContents;
		message.created_time = new Date(Long.parseLong("1331768446114"));
		message.updated_time = new Date(Long.parseLong("1331768446114"));
		
		for(User receiver : receivers) {
			message.addReceiver(receiver);
		}
		message.insert();
		
		// Create the outbox message
		OutboxMessage outMessage = new OutboxMessage(from, message);
		outMessage.save();	
		
				
		//Se inserta un mensaje que pertenece al receptor
			
		for(User receiver : receivers)	{
			InboxMessage inbox = new InboxMessage(receiver, message);
			inbox.readed = Boolean.TRUE;
			inbox.save();
		
			 Tag sharedTag = Tag.findOrCreateByName("shared", receiver);
				for(SharedContent sharedContent : sharedContents) {
					if(Content.ContentType.PHOTO == sharedContent.type) {
						ContentTag contentTag = new ContentTag(sharedContent.id, Content.ContentType.PHOTO, sharedTag);
						contentTag.save();
					}
				}
			
		}
		ok();
		
	}*/
	
/*	public static void get_old(Long id) {
		User current = getCurrentUser();
		Message message = Message.findById(id);
		if(message==null) notFound();
		if(message.owner.id.longValue() != current.id.longValue()) forbidden();
		renderTemplate("api/message.json",message);
	}
*/	
	public static void get(Long id) {
		User current = getCurrentUser();
		OutboxMessage message = OutboxMessage.getSent(id, current);
		if(message==null) notFound();
		//if(message.owner.id.longValue() != current.id.longValue()) forbidden();
		renderTemplate("api/message.json",message);
	}
	
	public static void delete(Long id) {
		User current = getCurrentUser();
		OutboxMessage message = OutboxMessage.getSent(id, current);
		if(message==null) notFound();
		//if(message.owner.id.longValue() != current.id.longValue()) forbidden();
		message.delete();
	}	
	
	/*public static void delete_old(Long id) {
		User current = getCurrentUser();
		Message message = Message.findById(id);
		if(message==null) notFound();
		if(message.owner.id.longValue() != current.id.longValue()) forbidden();
		message.delete();
	} */	
	
}